package com.lechi.web.job;

import com.lechi.iot.netty.channel.ITcpChannel;
import com.lechi.iot.netty.utils.BytesToHexUtil;
import com.lechi.iot.netty.utils.Hex;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.util.LeChiCacheUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * The type Send cmd job.
 *
 * @author yangguang
 */
@Slf4j
public class SendCmdJob implements Job {

    private static final ConcurrentHashMap<String, Semaphore> DEVICE_LOCKS = new ConcurrentHashMap<>();

    private static final ConcurrentHashMap<String, Long> DEVICE_DELAY_MAP = new ConcurrentHashMap<>();

    @Override
    public void execute(JobExecutionContext context) {
        var list = context.getMergedJobDataMap().get("deviceSn:cmd");
        for (Map<String, String> deviceSNAndCmdMap : (List<Map<String, String>>) list) {
            Set<Map.Entry<String, String>> setEntry = deviceSNAndCmdMap.entrySet();
            setEntry.forEach(entry -> {
                String deviceSN = entry.getKey();
                Semaphore semaphore = DEVICE_LOCKS.computeIfAbsent(deviceSN, k -> new Semaphore(1, true));
                try {
                    semaphore.acquire(); // 加锁
                    String hostName = GuavaCacheUtil.getBiDeviceSnAndIPMap().get(deviceSN);
                    byte[] sendMsg = BytesToHexUtil.hexStrToBinaryStr(entry.getValue());
                    if (Objects.isNull(deviceSN) || Objects.isNull(sendMsg) || Objects.isNull(hostName) || Objects.equals(deviceSN, hostName)) {
//                    log.error("指令：{} 暂停发送, 轮询任务待下发设备序列号：{}，设备IP地址：{}", entry.getValue(), deviceSN, hostName);
                        return;
                    }
                    ITcpChannel tcpChannel = LeChiCacheUtil.getTcpChannelMap().get(hostName);
                    long now = System.currentTimeMillis();
                    Long lastTime = DEVICE_DELAY_MAP.get(deviceSN);
                    if (lastTime != null && (now - lastTime) < 1000) {
                        TimeUnit.MILLISECONDS.sleep(1000 - (now - lastTime));
                    }
                    DEVICE_DELAY_MAP.put(deviceSN, System.currentTimeMillis());
                    ByteBuf byteBuf = Unpooled.wrappedBuffer(sendMsg);
                    Optional.ofNullable(tcpChannel).ifPresent(channel -> channel.send(byteBuf));
                    log.error("设备序列号：{}，设备地址：{}， 发送指令：{}", deviceSN, hostName, Hex.toHexString(sendMsg));
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    semaphore.release(); // 释放锁
                }
            });
        }
    }
}